package com.boot.down.service.impl;

import com.boot.down.exception.SecKillException;
import com.boot.down.service.OrderSecKillService;
import com.boot.down.util.redis.RedisLockMock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author dell
 */
@Slf4j
@Service
public class OrderSecKillServiceImpl implements OrderSecKillService {

	/**过期时间 10 s */
	private static final long TIMEOUT = 10 * 1000L;

	@Autowired
	private RedisLockMock redisLockMock;

	/**
	 * 商品
	 */
	static Map<String, Integer> products;
	/**
	 * 库存
	 */
	static Map<String, Integer> stock;
	/**
	 * 订单
	 */
	static Map<String, String> orders;


	//模拟表查询
	static {
		products = new HashMap<>();
		stock = new HashMap<>();
		orders = new HashMap<>();
		products.put("123123", 10000);
		stock.put("123123", 10000);
	}

	private String queryMap(String productId) {

		return "商品总数" + products.get(productId) + ", 剩余数量: " + stock.get(productId) + ", 已买数量:" + orders.size();
	}

	/**
	 * 1. 加上 synchronized 关键字, 进行方法的锁, 可以保证数据准确, 但是很慢, 而且只适合单点方法.
	 * 2. 利用redis的机制进行加锁
	 * @param productId 商品ID
	 * @return
	 */
	@Override
	public String secKillOrder(String productId) {

		//加锁
		long time = System.currentTimeMillis() + TIMEOUT;
		if(!redisLockMock.lock(productId, String.valueOf(time))){
		       throw new SecKillException(101, "人太多了, 换个姿势");
		}
		int stockNum = stock.get(productId);
		if(stockNum == 0){
			throw new SecKillException(100,"活动结束");
		}else{
			//模拟下单
            orders.put(String.valueOf(UUID.randomUUID()),productId);
            //减少库存
			stockNum = stockNum -1;
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			stock.put(productId, stockNum);
		}
		//解锁
		redisLockMock.unlock(productId, String.valueOf(time));
		return queryMap(productId);
	}

	@Override
	public String queryProductStock(String productId) {
		return this.queryMap(productId);
	}
}
